package com.rc.saas.tenant.config;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

/**
 * applicationContext-redis-session.xml
 * springboot2.x 使用LettuceConnectionFactory 代替 RedisConnectionFactory
 * 在application.yml/application.properties配置基本信息后,
 * springboot2.x  RedisAutoConfiguration能够自动装配:
 * LettuceConnectionFactory 和 RedisConnectionFactory 及其 RedisTemplate
 * Created by sven on 2019/10/7
 */
@Configuration
@EnableCaching //开启缓存，重要！！！
public class RedisConfig {
    @Value("${spring.redis.jedis.pool.max-active}")
    private int redisPoolMaxActive;

    //@Value("${spring.redis.jedis.pool.max-wait}")
    //private int redisPoolMaxWait;

    @Value("${spring.redis.jedis.pool.max-idle}")
    private int redisPoolMaxIdle;

    @Value("${spring.redis.jedis.pool.min-idle}")
    private int redisPoolMinIdle;

    @Autowired
    private RedisProperties redisProperties;

    @Autowired
    private JedisPoolConfig jedisPoolConfig;

    /**
     * RedisTemplate使用LettuceConnectionFactory连接工厂
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate redisTemplate(JedisConnectionFactory redisConnectionFactory) {
        //在SpringBoot2.0之后，spring容器是自动的生成了StringRedisTemplate和RedisTemplate<Object,Object>，
        //可以直接注入,但是在实际使用中，我们大多不会直接使用RedisTemplate<Object,Object>，
        // 而是会对key,value进行序列化

        //在自定义序列化过程，GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer大部分时候表现没有区别，实际上如果对象中有LinkedHashMap时候，后者会出错，这个以前坑了我很久，自我怀疑了很久。
        //建议使用GenericJackson2JsonRedisSerializer来序列化。
        //GenericJackson2JsonRedisSerializer和Jackson2JsonRedisSerializer都有一个问题，无法反序列化接口的动态代理类，原因应该是动态代理类没有缺省构造函数，对JPA的自定义结果集支持不好，对Page分页支持不好。

        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //配置序列化方式
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //使用fastjson 代替 GenericJackson2JsonRedisSerializer
        redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericFastJsonRedisSerializer());

        return redisTemplate;
    }

    /**
     * 配置redis连接池的配置 JedisPoolConfig
     * @return
     */
    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        //<!-- redis连接池的配置 -->
        //<bean id="jedisPoolConfig2" class="redis.clients.jedis.JedisPoolConfig">
        //    <property name="maxTotal" value="${redis.session.pool.maxTotal}"/>
        //    <property name="maxIdle" value="${redis.session.pool.maxIdle}"/>
        //    <property name="minIdle" value="${redis.session.pool.minIdle}"/>
        //    <property name="testOnBorrow" value="${redis.session.pool.testOnBorrow}"/>
        //    <property name="testOnReturn" value="${redis.session.pool.testOnReturn}"/>
        //</bean>

        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //最大连接数
        jedisPoolConfig.setMaxTotal(redisPoolMaxActive);
        //最小空闲连接数
        //jedisPoolConfig.setMaxIdle(redisProperties2.getMaxIdle());
        //当池内没有可用连接时，最大等待时间
        //jedisPoolConfig.setMaxWaitMillis(redisProperties2.getMaxWait());
        //jedisPoolConfig.setMinIdle(redisProperties2.getMaxIdle());
        jedisPoolConfig.setTestOnBorrow(true);
        jedisPoolConfig.setTestOnReturn(true);
        jedisPoolConfig.setTestWhileIdle(true);

        return jedisPoolConfig;
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        //IP
        redisStandaloneConfiguration.setHostName(redisProperties.getHost());
        //端口
        redisStandaloneConfiguration.setPort(redisProperties.getPort());
        //密码
        if (StringUtils.isNotEmpty(redisProperties.getPassword())) {
            redisStandaloneConfiguration.setPassword(redisProperties.getPassword());
        }
        JedisClientConfiguration.DefaultJedisClientConfigurationBuilder jpcb =
                (JedisClientConfiguration.DefaultJedisClientConfigurationBuilder) JedisClientConfiguration.builder();
        //jpcb.poolConfig(jedisPoolConfig());
        jpcb.poolConfig(jedisPoolConfig);

        //jpcb.readTimeout(Duration.ofMillis(redisProperties.getTimeout()));
        jpcb.readTimeout(redisProperties.getTimeout());

        //设置连接超时时间
        //jpcb.connectTimeout(Duration.ofMillis(redisProperties.getTimeout()));
        jpcb.connectTimeout(redisProperties.getTimeout());

        //设置是否使用池不需要传参数了，这个方法会将这个属性置为true。
        jpcb.usePooling();
        JedisClientConfiguration jedisClientConfiguration = jpcb.build();
        JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
        return factory;
    }

    //@Bean
    //public RedisConnectionFactory connectionFactory() {
    //    JedisPoolConfig poolConfig = new JedisPoolConfig();
    //    poolConfig.setMaxTotal(redisProperties2.getMaxActive());
    //    poolConfig.setMaxIdle(redisProperties2.getMaxIdle());
    //    poolConfig.setMaxWaitMillis(redisProperties2.getMaxWait());
    //    poolConfig.setMinIdle(redisProperties2.getMaxIdle());
    //    poolConfig.setTestOnBorrow(true);
    //    poolConfig.setTestOnReturn(false);
    //    poolConfig.setTestWhileIdle(true);
    //    JedisClientConfiguration jedisClientConfiguration = null;
    //
    //    if (redisProperties2.getSsl()){
    //        jedisClientConfiguration = JedisClientConfiguration.builder().usePooling().
    //                poolConfig(poolConfig).and().
    //                readTimeout(Duration.ofMillis(redisProperties2.getTimeout())).useSsl()
    //                .build();
    //    }else {
    //        jedisClientConfiguration = JedisClientConfiguration.builder().usePooling().
    //                poolConfig(poolConfig).and().
    //                readTimeout(Duration.ofMillis(redisProperties2.getTimeout())).build();
    //    }
    //    RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
    //
    //    redisStandaloneConfiguration.setDatabase(redisProperties2.getDatabase());
    //    redisStandaloneConfiguration.setPort(redisProperties2.getPort());
    //    redisStandaloneConfiguration.setPassword(RedisPassword.of(redisProperties2.getPassword()));
    //    redisStandaloneConfiguration.setHostName(redisProperties2.getHost());
    //    RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
    //    return redisConnectionFactory;
    //}

}
